﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace GameLogicProject
{
    enum NodeType
    {
        Market,
        SegmentationLevel,
        Strategy,
        Production,
        Company
    };

    class Option : IComparable
    {
        //Nome
        public string Name { get; set; }

        //Descricao
        public string Description { get; set; }

        //Tipo do nó. Pode ser "mercado", "nivelSegmentacao", "massas", etc
        public NodeType Type { get; set; }

        //Nivel do nó em relação à raiz da árvore
        //Parametro carregado no ficheiro de configuracao
        public Int32 Level { get; set; }

        //Conjunto de falas associadas ao nó
        public ArrayList Talks { get; set; }

        //Percentagem de influencia deste nó
        public double Influence { get; set; }

        //Opcoes possiveis a partir deste nó
        public List<Option> Options { get; set; }
        
        // Opcao do jogador
        // Corresponde ao indice da opção escolhida na lista Options
        public Int32 Choice { get; set; }

        //Se true, significa que jogador apenas tem de escolher uma das opções.
        //Se false significa que o jogador tem de fazer escolhas em todos os filhos. 
        //Se false, parametro Choice tem de ser nulo.
        //Ex. nó mercado não é finalNode porque jogador tem de escolher estratégia para todos os nós filhos: segmentação, organização, etc.
        public bool finalNode { get; set; }


        //PARA O PARSER
        public string attName { get; set; }
        public ArrayList OptionsName { get; set; }
        public string market { get; set; }


        
        public Option() 
        {
            this.Choice = -1;
            this.finalNode = true;
            this.Options = new List<Option>();
            this.OptionsName = new ArrayList();
            this.Talks = new ArrayList();

        }
        
        public Option(string name, string description)
        {
            this.Name = name;
            this.Description = description;
            this.finalNode = true;
            this.Choice = -1;
            this.Options = new List<Option>();
            this.OptionsName = new ArrayList();
            this.Talks = new ArrayList();
        }

        public Option(string name, string description, double influence)
        {
            this.Name = name;
            this.Description = description;
            this.Influence = influence;
            this.finalNode = true;
            this.Choice = -1;
            this.Options = new List<Option>();
            this.OptionsName = new ArrayList();
            this.Talks = new ArrayList();
        }

        public Option chooseOption()
        {
            if (this.Options.Count == 0)
            {
                return null;
            }
            Console.WriteLine("Opcao de " + this.Name);
            for (int i = 0; i < this.Options.Count; i++)
            {
                Console.WriteLine("   " + i + ": " + this.Options[i].Name);
            }

            string opcString = "";
            int opc = -1;
            while (opc < 0 || opc >= this.Options.Count)
            {
                Console.Write("Escolha: ");
                opcString = Console.ReadLine();
                if (int.TryParse(opcString, out opc) == true)
                    opc = int.Parse(opcString);
                else
                    opc = -1;
            }
            this.Choice = opc;

            return this.Options[opc];


        }



        // Metodo recursivo. Chamar com aux=0
        public ArrayList generateTalks(int numTalks)
        {
            //Retorna de nó nao tiver filhos
            if (Options.Count == 0)
            {
                return randomizeArray(this.Talks, numTalks);
            }

            //Se houver filhos 
            else
            {
                //Cria array com talks deste nó
                ArrayList higherLevelTalks = 
                    new ArrayList( randomizeArray(this.Talks, numTalks) );

                //Vai buscar falas do nó escolhido
                if (finalNode)
                {
                    higherLevelTalks.AddRange( ((Option) Options[Choice]).generateTalks(numTalks) );
                }

                //Vai buscar falas dos nós filhos. Como não é finalNode precisa das falas de todos os filhos
                else
                {
                    foreach (Option opt in this.Options)
                    {
                        higherLevelTalks.AddRange(opt.generateTalks(numTalks));
                    }
                }

                return higherLevelTalks;
            }
        }

        private ArrayList randomizeArray(ArrayList array, int size)
        {
            ArrayList generatedArray = new ArrayList();
            int generatedNumber = -1;
            Random rand = new Random();
            int max = array.Count;

            for (int i = 0; i < size; i++)
            {
                generatedNumber = rand.Next(max);
                generatedArray.Add(array[generatedNumber]);
            }

            return generatedArray;
        }



        public double generatePercentage()
        {
            //Console.WriteLine("Calcula Percentagem no: " + this.Name);
            //Retorna de nó nao tiver filhos
            if (Options.Count == 0)
            {
                //Console.WriteLine(this.Name + " Retorna Influencia: " + this.Influence);
                return this.Influence;
            }
            //Se houver filhos 
            else
            {
                double currentPercentage = 0;

                //Vai buscar percentagens do nó escolhido
                if (finalNode)
                {
                    currentPercentage = this.Influence;
                    currentPercentage *= ((Option)Options[Choice]).generatePercentage();
                    //Console.WriteLine(this.Name + " Final Node: " + currentPercentage);
                }

                //Vai buscar percentagens dos nós filhos. Como não é finalNode precisa das falas de todos os filhos
                else
                {
                    foreach (Option opt in this.Options)
                    {
                        currentPercentage += this.Influence*opt.generatePercentage();
                    }
                }

                //Console.WriteLine(this.Name + " Retorna currentPercentage: " + currentPercentage);
                return currentPercentage;
            }
        }



        public int CompareTo(object obj)
        {
            return this.attName.CompareTo(((Option)obj).attName);
        }
    }
}
